import pandas as pd
import requests
import os
import time
import random
import re
from urllib.parse import urlparse

# 全局变量
_current_proxy_index = 0

# 读取Excel文件
excel_file = '店铺.xlsx'
output_dir = 'url'

# 代理API URL
PROXY_API_URL = 'http://dddip.top/api/get?token=426e97524922b118745249567bd332&number=1000&type=https&format=1'
proxies_pool = []

# 获取下一个代理的函数
def get_next_proxy():
    global _current_proxy_index
    if len(proxies_pool) > 0:
        proxy = proxies_pool[_current_proxy_index]
        _current_proxy_index = (_current_proxy_index + 1) % len(proxies_pool)
        return proxy
    else:
        return None

# 确保输出目录存在
if not os.path.exists(output_dir):
    os.makedirs(output_dir)

# 从API获取代理IP列表
def get_proxies_from_api():
    try:
        print(f"正在从API获取代理IP...")
        response = requests.get(PROXY_API_URL, timeout=10)
        response.raise_for_status()
        
        # 解析API返回的代理IP列表
        proxies_text = response.text.strip()
        proxies_list = proxies_text.split('\r\n')
        
        # 去重处理
        original_count = len(proxies_list)
        proxies_list = list(set(proxies_list))  # 使用集合去重
        unique_count = len(proxies_list)
        if original_count > unique_count:
            print(f"已去除{original_count - unique_count}个重复代理IP")
        
        # 格式化代理IP为requests可用的格式
        # 注意：即使是HTTPS请求，也使用HTTP代理格式，这是处理SSL错误的推荐方式
        formatted_proxies = []
        for proxy in proxies_list:
            if proxy.strip():
                formatted_proxies.append({
                    'http': f'http://{proxy.strip()}',
                    'https': f'http://{proxy.strip()}'  # 关键修改：HTTPS请求也使用HTTP代理
                })
        
        print(f"成功获取{len(formatted_proxies)}个代理IP")
        return formatted_proxies
    except Exception as e:
        print(f"获取代理IP失败: {str(e)}")
        return []

# 初始化代理池
proxies_pool = get_proxies_from_api()

# 如果没有获取到代理，使用空代理（直接请求）
if not proxies_pool:
    proxies_pool = [None]

# 读取Excel文件内容
try:
    # 使用pandas读取Excel文件
    df = pd.read_excel(excel_file)
    
    # 显示前几行数据，确认列的顺序
    print("Excel文件内容预览:")
    print(df.head())
    
    # 获取总行数
    total_rows = len(df)
    print(f"共发现{total_rows}条记录")
    
    # 倒序遍历每行数据
    for index, row in df.iloc[::-1].iterrows():
        try:
            # 获取第一列作为文件名（店铺名）
            shop_name = str(row.iloc[0]).strip()
            # 获取第二列作为网址
            url = str(row.iloc[1]).strip()
            
            # 跳过无效数据
            if not shop_name or not url or url.lower() == 'nan':
                print(f"跳过第{total_rows - index}行：无效的店铺名或网址")
                continue
            
            # 倒序处理时，计算正确的进度显示
            reversed_index = total_rows - index
            print(f"正在处理倒序第{reversed_index}/{total_rows}条：{shop_name} - {url}")
            
            # 预先计算文件名并检查文件是否存在
            # 清理文件名，移除非法字符
            valid_filename = "".join([c for c in shop_name if c.isalnum() or c in (' ', '_', '-', '.')])
            valid_filename = valid_filename.replace(' ', '_')
            
            # 添加前置0，确保文件名长度为5位数
            # 提取数字部分并填充
            digits = ''.join(filter(str.isdigit, valid_filename))
            if digits:
                padded_digits = digits.zfill(5)
                valid_filename = valid_filename.replace(digits, padded_digits)
            
            # 计算完整文件路径
            file_path = os.path.join(output_dir, f"{valid_filename}.txt")
            
            # 检查文件是否已存在，如果存在则跳过
            if os.path.exists(file_path):
                print(f"文件已存在，跳过读取：{file_path}")
                continue
            
            # 文件不存在，继续处理
            # 发送请求获取网页源码
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            }
            
            # 确保URL格式正确
            if not url.startswith(('http://', 'https://')):
                url = 'http://' + url
            
            # 获取下一个可用代理
            proxy = get_next_proxy()
            
            # 发送请求，设置超时时间为10秒，使用代理
            # 增加重试机制和直接请求备选
            max_retries = 3
            retry_count = 0
            success = False
            
            while retry_count < max_retries and not success:
                try:
                    if retry_count == 0 and proxy:
                        print(f"使用代理: {proxy['http']}")
                        response = requests.get(url, headers=headers, proxies=proxy, timeout=10)
                    else:
                        # 如果是重试，或没有可用代理，尝试直接请求
                        if retry_count > 0:
                            print(f"第{retry_count+1}次尝试，使用直接请求")
                        else:
                            print("无可用代理，使用直接请求")
                        response = requests.get(url, headers=headers, timeout=10)
                    response.raise_for_status()  # 如果状态码不是200，抛出异常
                    success = True
                except requests.exceptions.ProxyError:
                    retry_count += 1
                    print(f"代理{proxy['http'] if proxy else '未知'}不可用，尝试移除")
                    if proxy and proxy in proxies_pool:
                        proxies_pool.remove(proxy)
                    # 如果代理池为空，尝试重新获取代理
                    if not proxies_pool:
                        proxies_pool = get_proxies_from_api()
                    # 获取新的代理
                    proxy = get_next_proxy()
                    # 如果重试次数已用完，抛出异常
                    if retry_count >= max_retries:
                        raise
                except requests.exceptions.Timeout:
                    retry_count += 1
                    print(f"请求超时，尝试第{retry_count+1}次")
                    # 移除当前失败的代理
                    if proxy and proxy in proxies_pool:
                        proxies_pool.remove(proxy)
                        print(f"从代理池中移除超时代理: {proxy['http']}")
                    # 更换代理
                    proxy = get_next_proxy()
                    # 如果代理池为空，尝试重新获取代理
                    if not proxies_pool:
                        proxies_pool = get_proxies_from_api()
                    if retry_count >= max_retries:
                        raise
                except requests.exceptions.ConnectionError as e:
                    retry_count += 1
                    print(f"连接错误({str(e)})，尝试第{retry_count+1}次")
                    # 移除当前失败的代理
                    if proxy and proxy in proxies_pool:
                        proxies_pool.remove(proxy)
                        print(f"从代理池中移除连接错误代理: {proxy['http']}")
                    # 更换代理
                    proxy = get_next_proxy()
                    # 如果代理池为空，尝试重新获取代理
                    if not proxies_pool:
                        proxies_pool = get_proxies_from_api()
                    if retry_count >= max_retries:
                        raise
            
            # 获取网页源码
            html_content = response.text
            
            # 检查网页内容是否包含"义乌购-登录"文本
            if "义乌购-登录" in html_content:
                print(f"检测到\"义乌购-登录\"文本，尝试使用新代理重新获取")
                
                # 标记当前代理为不可用
                if proxy and proxy in proxies_pool:
                    proxies_pool.remove(proxy)
                    print(f"移除不可用代理: {proxy['http']}")
                
                # 如果代理池为空，尝试重新获取代理
                if not proxies_pool:
                    proxies_pool = get_proxies_from_api()
                    if not proxies_pool:
                        proxies_pool = [None]
                
                # 获取下一个代理并重新请求
                proxy = get_next_proxy()
                
                # 使用新代理重新请求
                try:
                    if proxy:
                        print(f"使用新代理: {proxy['http']} 重新请求")
                        response = requests.get(url, headers=headers, proxies=proxy, timeout=10)
                    else:
                        print("无可用代理，使用直接请求重新尝试")
                        response = requests.get(url, headers=headers, timeout=10)
                    response.raise_for_status()
                    html_content = response.text
                    print("使用新代理重新请求成功")
                except Exception as e:
                    print(f"使用新代理重新请求失败: {str(e)}")
                    # 保留原始响应内容，继续处理
            
            # 文件名和路径已经在前面计算过了，直接使用
            # 保存源码到文件
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(html_content)
            
            print(f"成功保存：{file_path}")
            
            # 添加随机延迟，避免请求过于规律
            time.sleep(random.uniform(1, 3))
            
        except requests.exceptions.RequestException as e:
            print(f"请求失败 ({shop_name} - {url})：{str(e)}")
        except Exception as e:
            print(f"处理失败 ({shop_name} - {url})：{str(e)}")
    
    print("所有店铺网址爬取完成！")
    
except Exception as e:
    print(f"读取Excel文件失败：{str(e)}")
    print("请检查文件是否存在，以及是否安装了pandas和openpyxl库。")
    print("安装命令：pip install pandas openpyxl requests")